package cn.edu.cug.cs.gtl.docsrv.txt;

import cn.edu.cug.cs.gtl.common.Pair;
import cn.edu.cug.cs.gtl.docsrv.config.Configuration;
import cn.edu.cug.cs.gtl.docsrv.doc.DocManager;
import cn.edu.cug.cs.gtl.io.FileDataSplitter;
import cn.edu.cug.cs.gtl.mybatis.Session;
import cn.edu.cug.cs.gtl.mybatis.mapper.doc.DocAll;
import cn.edu.cug.cs.gtl.mybatis.mapper.txt.*;
import cn.edu.cug.cs.gtl.mybatis.mapper.txt.TxtAll;
import cn.edu.cug.cs.gtl.mybatis.mapper.txt.TxtFile;
import cn.edu.cug.cs.gtl.mybatis.mapper.txt.TxtItem;
import cn.edu.cug.cs.gtl.mybatis.metadata.TxtUtils;
import cn.edu.cug.cs.gtl.protos.Document;
import cn.edu.cug.cs.gtl.protos.TimeValue;
import cn.edu.cug.cs.gtl.protoswrapper.TimeValueWrapper;
import org.locationtech.jts.geom.Envelope;

import java.io.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class LocalTxtManager extends TxtManager {

    /**
     * 构造函数
     *
     * @param session
     */
    public LocalTxtManager(Session session) {
        super(session);
        File f = new File(Configuration.getManagerConfig().getLocalTxtDataRoot());
        if(!f.exists()){
            f.mkdirs();
        }
        File fTmp = new File(Configuration.getManagerConfig().getLocalDataRoot()+File.separator+"tmp");
        if(!fTmp.exists()){
            fTmp.mkdirs();
        }
    }

    public String getDataRoot(){
        return Configuration.getManagerConfig().getLocalTxtDataRoot();
    }
    /**
     * 将TxtUrl解析成localDir和localFileName
     * @param url  格式为  file:/data/tmp/txtExample.zip
     *                    file:D:/data/tmp/txtExample.zip
     * @return 解析后的结果为
     * localDir = /data/tmp
     * localFileName=txtExample.zip
     */
    private static  Pair<String,String> parseTxtUrl(String url){
        String[] ss = cn.edu.cug.cs.gtl.io.File.split(url);
        String remoteFileName = ss[ss.length - 1];
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 1; i < ss.length - 1; i++) {
            stringBuilder.append(File.separator);
            stringBuilder.append(ss[i]);
        }

        String remoteDir = stringBuilder.toString();
        //如果是在Windows下，需要处理盘符
        String [] ws = ss[0].split(":");
        if(ws.length>1){
            if(!ws[1].isEmpty())
                remoteDir = ws[1]+":"+remoteDir;
        }
        Pair<String,String> p = new Pair<>(remoteDir,remoteFileName);
        return p;
    }

    /**
     *
     * @param txtItem
     * @param txtFile
     * @return
     * @throws Exception
     */
    protected static boolean writeToFileSystem(TxtItem txtItem, TxtFile txtFile) throws Exception{
        //写入本地文件系统
        Pair<String, String> p = parseTxtUrl(txtItem.getTxtUrl());
        File f = new File(p.first()+File.separator+p.second());
        OutputStream outputStream = new FileOutputStream(f);
        outputStream.write(txtFile.getTxtRawBytes());
        outputStream.close();
        return true;
    }

    /**
     *
     * @param localDir
     * @param localFileName
     * @return
     * @throws Exception
     */
    protected static TxtFile readFromFileSystem(String localDir, String localFileName) throws Exception{
        File f = new File(localDir +File.separator+ localFileName);
        InputStream inputStream = new FileInputStream(f);
        int len = (int)f.length();
        TxtFile txtFile = new TxtFile();
        byte[] bytes = new byte[len];
        inputStream.read(bytes);
        txtFile.setTxtRawBytes(bytes);
        inputStream.close();
        return txtFile;
    }

    /**
     * 将一个由txtItem+txtFile组成的图形文档插入数据库
     *
     * @param txtItem 图形元数据信息,
     *                其中的txtUrl一定要设置值，形式如下
     *                file:/data/tmp/txtExample.zip
     * @param txtFile 图形文件内容
     * @return
     */
    @Override
    public boolean insert(TxtItem txtItem, TxtFile txtFile) {
        try {
            writeToFileSystem(txtItem,txtFile);
            //写入元数据
            TxtItemMapper txtItemMapper = session.getMapper(TxtItemMapper.class);
            txtItemMapper.insert(txtItem);
            session.commit();
            return true;
        }
        catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 将TxtAll分解成TxtItem和TxtFile，
     * 然后将TxtItem插入数据表SHP_ITEM，
     * 将TxtFile插入数据表SHP_FILE，
     * @param txtAll
     * @return
     */
    @Override
    public boolean insert(TxtAll txtAll) {
        Pair<TxtItem,TxtFile> p = TxtUtils.fromTxtAll(txtAll);
        return insert(p.getFirst(),p.getSecond());
    }

    /**
     * 读取本地目录中的所有图形文档，将其插入图形库中
     *
     * @param localDir 本地目录
     * @return 成功返回true, 否则返回false
     */
    @Override
    public boolean insert(String localDir) {
        try {

            File file = new File(localDir);
            if (!file.isDirectory())
                return false;
            File parent = file.getParentFile();

            List<TxtCatalog> catalogs = localDirToCatalogs(localDir);
            for(TxtCatalog txtCatalog: catalogs){
                file = new File(parent.getAbsolutePath()+File.separator+txtCatalog.getCatalogName());
                if(!file.exists() || !file.isDirectory())
                    continue;

                File[] files = file.listFiles();
                for (File f : files) {
                    if(f.isDirectory()){
                        continue;
                    }
                    Pair<TxtItem,TxtFile> p = parseTxtFiles(f);

                    if(p==null)  continue;

                    //设置SHPItem
                    TxtItemMapper txtItemMapper = session.getMapper(TxtItemMapper.class);
                    p.first().setTxtInternalId(txtItemMapper.maxInternalId().add(BigDecimal.ONE));
                    StringBuilder txtUrl=new StringBuilder();
                    txtUrl.append("file:");
                    txtUrl.append(Configuration.getManagerConfig().getLocalTxtDataRoot());
                    txtUrl.append(File.separator);
                    txtUrl.append(f.getName().replace("txt","zip").trim());
                    p.first().setTxtUrl(txtUrl.toString());
                    p.first().setTxtCatalog(txtCatalog.getCatalogInternalId());
                    txtItemMapper.insert(p.first());
                    session.commit();

                    writeToFileSystem(p.first(),p.second());
                }
            }

        }
        catch (Exception e){
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 读取本地目录中的所有图形文档，将其插入图形库中
     * 不管Catalog相关信息的处理，直接插入数据库中
     * @param localDir 本地目录
     * @return 成功返回true, 否则返回false
     */
    public boolean insertWithoutCatalog(String localDir) {
        try {

            File file = new File(localDir);
            if (!file.isDirectory())
                return false;
            File[] files = file.listFiles();
            for (File f : files) {
                if(f.isDirectory()){
                    return insert(f.getCanonicalPath());
                }

                Pair<TxtItem,TxtFile> p = parseTxtFiles(f);

                if(p==null)  continue;

                //设置SHPItem
                TxtItemMapper txtItemMapper = session.getMapper(TxtItemMapper.class);
                p.first().setTxtInternalId(BigDecimal.valueOf(txtItemMapper.maxInternalId().doubleValue()+1));
                StringBuilder txtUrl=new StringBuilder();
                txtUrl.append("file:");
                txtUrl.append(Configuration.getManagerConfig().getLocalTxtDataRoot());
                txtUrl.append(File.separator);
                txtUrl.append(f.getName().replace("txt","zip").trim());
                p.first().setTxtUrl(txtUrl.toString());

                txtItemMapper.insert(p.first());
                session.commit();

                writeToFileSystem(p.first(),p.second());
            }
        }
        catch (Exception e){
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 根据txtInternalId删除数据库中对应的图形文档记录
     *
     * @param txtItem 必须填充txtInternalId和txtUrl
     * @return
     */
    @Override
    public boolean delete(TxtItem txtItem) {
        try{
            TxtItemMapper txtItemMapper = session.getMapper(TxtItemMapper.class);
            txtItemMapper.deleteByPrimaryKey(txtItem.getTxtInternalId());
            session.commit();
            Pair<String,String> p = parseTxtUrl(txtItem.getTxtUrl());
            File f = new File(p.first()+File.separator+p.second());
            if(f.exists())
                f.delete();
            return true;
        }
        catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 根据Id删除图形库中的元数据和内容数据
     * @param txtAll 必须填充txtInternalId和txtUrl
     * @return
     */
    @Override
    public boolean delete(TxtAll txtAll) {
        Pair<TxtItem,TxtFile> p = TxtUtils.fromTxtAll(txtAll);
        return delete(p.first());
    }

    /**
     * 根据txtItem+txtFile更新数据库中的图形文档记录
     *
     * @param txtItem 该对象的txtInternalId必须填充,
     *                txtUrl必须填充
     * @param txtFile 更新文档文件的内容
     * @return 更新成功返回true, 否则返回false
     */
    @Override
    public boolean update(TxtItem txtItem, TxtFile txtFile) {
        try{
            TxtItemMapper txtItemMapper = session.getMapper(TxtItemMapper.class);
            txtItemMapper.updateByPrimaryKey(txtItem);

            Pair<String,String> p = parseTxtUrl(txtItem.getTxtUrl());
            File f = new File(p.first()+File.separator+p.second());
            boolean b = f.exists();
            if(b) f.delete();
            return writeToFileSystem(txtItem,txtFile);
        }
        catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    /**
     *根据TxtAll中的内容更新图形库中对应的信息
     * @param txtAll 该对象的txtInternalId必须填充
     * @return
     */
    @Override
    public boolean update(TxtAll txtAll) {
        Pair<TxtItem,TxtFile> p = TxtUtils.fromTxtAll(txtAll);
        return update(p.first(),p.second());
    }

    /**
     * 根据ID查询图形块信息
     * @param txtInternalId
     * @return
     */
    @Override
    public TxtAll queryByInternalId(BigDecimal txtInternalId) {
        try{
            TxtItemMapper txtItemMapper = session.getMapper(TxtItemMapper.class);
            TxtItem txtItem = txtItemMapper.selectByPrimaryKey(txtInternalId);
            Pair<String,String> p = parseTxtUrl(txtItem.getTxtUrl());


            TxtFile txtFile = readFromFileSystem(p.first(),p.second());
            txtFile.setTxtInternalId(txtInternalId);

            TxtAll txtAll = TxtUtils.toTxtAll(txtItem,txtFile);
            return txtAll;
        }
        catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据英文标题查询图形内容
     * @param txtEnTitle
     * @return
     */
    @Override
    public List<TxtAll> queryByEnTitle(String txtEnTitle){
        List<TxtAll> res = new ArrayList<>();
        try{
            TxtItemMapper txtItemMapper = session.getMapper(TxtItemMapper.class);
            List<TxtItem> txtItems = txtItemMapper.selectByEnTitle(txtEnTitle);
            for(TxtItem txtItem: txtItems){
                Pair<String,String> p = parseTxtUrl(txtItem.getTxtUrl());
                TxtFile txtFile = readFromFileSystem(p.first(),p.second());
                txtFile.setTxtInternalId(txtItem.getTxtInternalId());

                TxtAll txtAll = TxtUtils.toTxtAll(txtItem,txtFile);
                res.add(txtAll);
            }
            return res;
        }
        catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据中文标题查询图形内容
     * @param txtCnTitle  文档注释
     * @return
     */
    @Override
    public List<TxtAll> queryByComment(String txtCnTitle) {
//        List<TxtAll> res = new ArrayList<>();
//        try{
//            TxtItemMapper txtItemMapper = session.getMapper(TxtItemMapper.class);
//            List<TxtItem> txtItems = txtItemMapper.selectByCnTitle(txtCnTitle);
//            for(TxtItem txtItem: txtItems){
//                Pair<String,String> p = parseTxtUrl(txtItem.getTxtUrl());
//                TxtFile txtFile = readFromFileSystem(p.first(),p.second());
//                txtFile.setTxtInternalId(txtItem.getTxtInternalId());
//
//                TxtAll txtAll = TxtUtils.toTxtAll(txtItem,txtFile);
//                res.add(txtAll);
//            }
//            return res;
//        }
//        catch (Exception e){
//            e.printStackTrace();
//        }
        return null;
    }

    /**
     * 根据类型查询图形信息
     * @param txtType
     * @return
     */
    @Override
    public List<TxtAll> queryByType(String txtType) {
//        List<TxtAll> res = new ArrayList<>();
//        try{
//            TxtItemMapper txtItemMapper = session.getMapper(TxtItemMapper.class);
//            List<TxtItem> txtItems = txtItemMapper.selectByType(txtType);
//            for(TxtItem txtItem: txtItems){
//                Pair<String,String> p = parseTxtUrl(txtItem.getTxtUrl());
//                TxtFile txtFile = readFromFileSystem(p.first(),p.second());
//                txtFile.setTxtInternalId(txtItem.getTxtInternalId());
//                TxtAll txtAll = TxtUtils.toTxtAll(txtItem,txtFile);
//                res.add(txtAll);
//            }
//            return res;
//        }
//        catch (Exception e){
//            e.printStackTrace();
//        }
        return null;
    }

    /**
     * 根据添加入库时间查询图形
     * @param begin 开始时间
     * @param end  结束时间
     * @return
     */
    @Override
    public List<TxtAll> queryByAppendDate(TimeValue begin, TimeValue end) {
//        List<TxtAll> res = new ArrayList<>();
//        try{
//            TxtItemMapper txtItemMapper = session.getMapper(TxtItemMapper.class);
//            List<TxtItem> txtItems =  txtItemMapper.selectByAppendDate(TimeValueWrapper.toUtilDate(begin),TimeValueWrapper.toUtilDate(end));
//            for(TxtItem txtItem: txtItems){
//                Pair<String,String> p = parseTxtUrl(txtItem.getTxtUrl());
//                TxtFile txtFile = readFromFileSystem(p.first(),p.second());
//                txtFile.setTxtInternalId(txtItem.getTxtInternalId());
//                TxtAll txtAll = TxtUtils.toTxtAll(txtItem,txtFile);
//                res.add(txtAll);
//            }
//            return res;
//        }
//        catch (Exception e){
//            e.printStackTrace();
//        }
        return null;
    }

    /**
     * 根据传入参数在图形库中进行查询
     *       try {
     *             Map<String,Object> p = new LinkedHashMap<String,Object>();
     *             p.put("txtInternalId",BigDecimal.valueOf(1));
     *             List<TxtItem> r1 = this.query(p);
     *             p.clear();
     *             p.put("txtEnTile","aaa");
     *             p.put("txtCnTile","zhangsan");
     *             List<TxtItem> r2 = this.query(p);
     *             boolean b = r1.size()==r2.size();
     *         }
     *         catch (Exception e){
     *             e.printStackTrace();
     *         }
     * @param parameters
     *     BigDecimal txtInternalId;
     *
     *     String txtEnTitle;
     *
     *     String txtCnTitle;
     *
     *     String txtUuid;
     *
     *     String txtVersion;
     *
     *     String txtKeywords;
     *
     *     String txtAbstract;
     *
     *     String txtContent;
     *
     *     String txtType;
     *
     *     String txtAuthors;
     *
     *     String txtAffiliation;
     *
     *     String txtTags;
     *
     *     String txtUrl;
     *
     *     Date txtAppendDate;
     *
     *     Date txtUpdateDate;
     *
     *     Date txtCreateDate;
     *
     *     String txtMemo;
     *
     *     BigDecimal txtCatalog;
     *
     *     String txtExtent;
     *
     *     byte[] txtRawBytes;
     * @return 返回查询到的文档。
     */
    @Override
    public List<TxtAll> query(Map<String, Object> parameters) {

//        List<TxtAll> res = new ArrayList<>();
//        try{
//            TxtItemMapper txtItemMapper = session.getMapper(TxtItemMapper.class);
//            List<TxtItem> txtItems =  txtItemMapper.query(parameters);
//            for(TxtItem txtItem: txtItems){
//                Pair<String,String> p = parseTxtUrl(txtItem.getTxtUrl());
//                TxtFile txtFile = readFromFileSystem(p.first(),p.second());
//                txtFile.setTxtInternalId(txtItem.getTxtInternalId());
//                TxtAll txtAll = TxtUtils.toTxtAll(txtItem,txtFile);
//                res.add(txtAll);
//            }
//            return res;
//        }
//        catch (Exception e){
//            e.printStackTrace();
//        }
        return null;
    }

    @Override
    public List<BigDecimal> getTxtInternalIdsByCatalogInternalId(BigDecimal catalogId) {
        return null;
    }

//    @Override
//    public BlockQuerier getBlockQuerier() {
//        return null;
//    }
//
//    @Override
//    public BlockUpdater getBlockUpdater() {
//        return null;
//    }

    /**
     * 获取图形块ShapeBlock级别的查询器
     *
     * @return
     */
//    @Override
//    public BlockQuerier getBlockQuerier() {
//        return new DefaultBlockQuerier(this);
//    }

    /**
     * 获取图形块ShapeBlock级别的更新器
     * @return
     */
//    @Override
//    public BlockUpdater getBlockUpdater() {
//        return new DefaultBlockUpdater(this);
//    }

    /**
     * 查询得到所有ShapeBlock的边界矩形
     * @return
     */
    @Override
    public  List<Pair<BigDecimal, Envelope>> queryAllEnvelopes(){
//        try {
//            TxtItemMapper txtItemMapper = session.getMapper(TxtItemMapper.class);
//            List<LinkedHashMap<String, Object>> ls = txtItemMapper.selectAllInternalIdAndExtents();
//            System.out.println(ls.size());
//            List<Pair<BigDecimal, Envelope>> r = new ArrayList<>();
//            for (LinkedHashMap<String, Object> l: ls){
//                BigDecimal id = (BigDecimal)l.get("SHP_INTERNAL_ID");
//                String coords = (String)l.get("SHP_EXTENT");
//                String [] cs = coords.split(FileDataSplitter.COMMA.getDelimiter());
//                double minX = Double.valueOf(cs[0]).doubleValue();
//                double maxX = Double.valueOf(cs[1]).doubleValue();
//                double minY = Double.valueOf(cs[2]).doubleValue();
//                double maxY = Double.valueOf(cs[3]).doubleValue();
//                Envelope envelope = new Envelope(minX,maxX,minY,maxY);
//                r.add(new Pair<>(id,envelope));
//            }
//            return r;
//        }
//        catch (Exception e){
//            e.printStackTrace();
//        }
        return null;
    }



}
